#if defined(ARCTIC)
/**
 @file sys_tmm_linkagg.c

 @date 2018-9-21

 @version v1.0

 The file contains TMM Linkagg APIs of sys layer
*/

/***************************************************************
 *
 * Header Files
 *
 ***************************************************************/

#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_register.h"
#include "sys_usw_common.h"
#include "sys_usw_chip.h"
#include "sys_usw_linkagg.h"
#include "sys_usw_datapath.h"
#include "sys_usw_dmps.h"
#include "sys_usw_qos_api.h"
#include "drv_api.h"

extern int32
_sys_tmm_linkagg_dlb_set_quality_map(uint8 lchip, uint8 tx_load_percent);

extern int32
sys_usw_linkagg_get_member_list(uint8 lchip, uint16 tid, uint16* member_list, uint8* p_member_cnt);

extern int32
_sys_usw_linkagg_get_ports2(uint8 lchip, sys_linkagg_t* p_group, uint32* member_list, uint8* p_member_cnt);

extern int32
_sys_usw_linkagg_create_channel_agg(uint8 lchip, ctc_linkagg_group_t* p_linkagg_grp);
extern int32
_sys_usw_linkagg_destroy_channel_agg(uint8 lchip, uint8 tid);
extern int32
_sys_usw_linkagg_add_channel_member(uint8 lchip, uint8 tid, uint32 chan_id);
extern int32
_sys_usw_linkagg_remove_channel_member(uint8 lchip, uint8 tid, uint32 chan_id);

int32
_sys_at_linkagg_get_profile_by_speed_mode(uint8 lchip, uint32 gport, uint32 *value)
{
    uint32 speed_mode = 0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};

    dmps_port_info.gport = gport;
    CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_SPEED_MODE, &speed_mode));
    switch (speed_mode)
    {
        case CTC_PORT_SPEED_10M:
        case CTC_PORT_SPEED_100M:
        case CTC_PORT_SPEED_1G:
        case CTC_PORT_SPEED_2G5:
            *value = 0;  /* 1G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_5G:
            *value = 1;  /* 5G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_10G:
            *value = 2;  /* 10G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_20G:
            *value = 3;  /* 20G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_25G:
            *value = 4;  /* 25G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_40G:
            *value = 5;  /* 40G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_50G:
            *value = 6;  /* 50G, get channel type by datapath */
            break;

        case CTC_PORT_SPEED_100G:
            *value = 7;  /* 100G, get channel type by datapath */
            break;
        default:
            *value = 7;
            break;
    }
    return CTC_E_NONE;
}

int32
_sys_at_linkagg_dlb_set_load_quality_threshold(uint8 lchip, uint32 min_th, uint32 max_th)
{
    uint32 cmd = 0;
    uint32 th_bytes = 0;
    uint32 th_step = 0;
    uint32 factors[] = { 1, 5, 10, 20, 25, 40, 50, 100};
    uint8 i = 0;
    uint8 j = 0;
    DsEpeHeaderEditChanLoadQuantizationProfile_m lag_dlb_load_threshold;

    if (min_th > max_th) {
        max_th = min_th;
    }

    if (max_th * factors[7] > 0xffffff) {
        /* Hardware limits load size threshold to 24 bits */
        return CTC_E_INVALID_PARAM;
    }

    for(i = 0; i < 8; i++)
    {
        sal_memset(&lag_dlb_load_threshold, 0, sizeof(lag_dlb_load_threshold));

        th_step = (max_th - min_th)  / 14;
        for (j = 0; j < 15; j++)
        {
            th_bytes = (min_th + j * th_step) * factors[i];
            SetDsEpeHeaderEditChanLoadQuantizationProfile(V, g_0_threshold_f + j, &lag_dlb_load_threshold, th_bytes);
        }

        cmd = DRV_IOW(DsEpeHeaderEditChanLoadQuantizationProfile_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, i, cmd, &lag_dlb_load_threshold));
    }

    return CTC_E_NONE;
}

int32
_sys_at_linkagg_dlb_set_qdepth_quality_threshold(uint8 lchip, uint32 min_th, uint32 max_th)
{
    uint32 cmd = 0;
    uint32 th_cells = 0;
    uint32 th_step = 0;
    uint32 factors[] = { 1, 5, 10, 20, 25, 40, 50, 100};
    uint8 i = 0;
    uint8 j = 0;

    DsErmChanSizeQuantizationProfile_m lag_dlb_qdepth_threshold;

    if (min_th > max_th) {
        max_th = min_th;
    }

    if (max_th * factors[7] > 0x3ffff) {
        /* Hardware limits queue depth threshold to 18 bits */
        return CTC_E_INVALID_PARAM;
    }

    for (i = 0; i < 8; i++)
    {
        sal_memset(&lag_dlb_qdepth_threshold, 0, sizeof(lag_dlb_qdepth_threshold));

        th_step = (max_th - min_th)  / 14;
        for (j = 0; j < 15; j++)
        {
            th_cells = (min_th + j * th_step) * factors[i];
            SetDsErmChanSizeQuantizationProfile(V, g_0_threshold_f + j, &lag_dlb_qdepth_threshold, th_cells);
        }

        cmd = DRV_IOW(DsErmChanSizeQuantizationProfile_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, i, cmd, &lag_dlb_qdepth_threshold));
    }

    return CTC_E_NONE;
}
int32
sys_at_linkagg_dlb_init(uint8 lchip)
{
    uint32 value = 0;
    uint32 cmd = 0;
    uint32 tx_load_percent = 0;
    uint32 port_type = 0;
    uint32 pp_id = 0;
    uint32 dp_id = 0;
    uint32 sub_chan = 0;
    uint32 index = 0;
    uint16 i = 0;
    uint16 j = 0;
    uint16 chan_id = 0;
    uint16 lport = 0;
    uint8 step = 0;
    uint8 gchip = 0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};

    DsEpeHeaderEditChanLoadWeight_m chan_load_weight;
    DsErmChanSizeWeight_m chan_size_weight;
    DsEpeHeaderEditDreDiscountShift_m dre_shift;
    LagDlbQualityMapCtl_m lag_dlb_quality_map_ctl;
    EpeHeaderEditChanAvgLoadTimerCtl_m lag_engine_avg_load_ctl;
    ErmChanAvgSizeTimerCtl_m  lag_engine_avg_qdepth_ctl;
    EpeHeaderEditChanAvgLoadTimerCtl_m lag_engine_dlb_ctl;
    LagEngineCtl_m lag_engine_ctl;
    ErmChanSizeUpdateCtl_m chan_size_updte;
    RefDivSlice0PPPulse_m ref_div_pp_pulse;

    sal_memset(&lag_dlb_quality_map_ctl, 0, sizeof(lag_dlb_quality_map_ctl));
    sal_memset(&lag_engine_avg_load_ctl, 0, sizeof(lag_engine_avg_load_ctl));
    sal_memset(&lag_engine_avg_qdepth_ctl, 0, sizeof(lag_engine_avg_qdepth_ctl));
    sal_memset(&lag_engine_dlb_ctl, 0, sizeof(lag_engine_dlb_ctl));
    sal_memset(&lag_engine_ctl, 0, sizeof(lag_engine_ctl));
    sal_memset(&ref_div_pp_pulse, 0, sizeof(ref_div_pp_pulse));

    /*1.config LagDlbQualityMapCtl_m*/
    tx_load_percent = 100;
    CTC_ERROR_RETURN(_sys_tmm_linkagg_dlb_set_quality_map(lchip, tx_load_percent));
    sys_usw_get_gchip_id(lchip, &gchip);
    step = DsEpeHeaderEditChanLoadWeight_g_1_profileId_f - DsEpeHeaderEditChanLoadWeight_g_0_profileId_f;

    do
    {
        dmps_port_info.gport = CTC_MAP_LPORT_TO_GPORT(gchip, lport);
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PORT_TYPE, &port_type));
        if (port_type != SYS_DMPS_NETWORK_PORT)
        {
            continue;
        }
        CTC_ERROR_RETURN(_sys_at_linkagg_get_profile_by_speed_mode(lchip, dmps_port_info.gport, &value));
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PP_ID, &pp_id));
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_DP_ID, &dp_id));
        CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_SUB_CHAN_ID, &sub_chan));

        cmd = DRV_IOR(DsEpeHeaderEditChanLoadWeight_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + pp_id, sub_chan, DRV_CMD_PP_EN(cmd), &chan_load_weight));
        SetDsEpeHeaderEditChanLoadWeight(V, g_0_profileId_f + step * dp_id, &chan_load_weight, value);
        cmd = DRV_IOW(DsEpeHeaderEditChanLoadWeight_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + pp_id, sub_chan, DRV_CMD_PP_EN(cmd), &chan_load_weight));

        index = (sub_chan < 16) ? ((sub_chan >> 3) + (pp_id << 2) + (dp_id << 1))
                                 : (32 + (pp_id << 1) + dp_id);
        cmd = DRV_IOR(DsErmChanSizeWeight_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &chan_size_weight));
        SetDsErmChanSizeWeight(V, g_0_profileId_f + (sub_chan & 0x7), &chan_size_weight, value);
        cmd = DRV_IOW(DsErmChanSizeWeight_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &chan_size_weight));
    } while (++lport < MCHIP_CAP(SYS_CAP_PER_SLICE_PORT_NUM));

    /*3.config EpeHeaderEditChanAvgLoadTimerCtl*/
    cmd = DRV_IOR(EpeHeaderEditChanAvgLoadTimerCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_avg_load_ctl));
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEn_f, &lag_engine_avg_load_ctl, 1);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerInterval_f, &lag_engine_avg_load_ctl, 10);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerDreOptimizeEn_f, &lag_engine_avg_load_ctl, 0);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEwmaWeight_f, &lag_engine_avg_load_ctl, 0);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEwmaDecOptimizeEn_f, &lag_engine_avg_load_ctl, 0);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEwmaMode_f, &lag_engine_avg_load_ctl, 0);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerPtrMax_f, &lag_engine_avg_load_ctl, 51);
    SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerPtrMin_f, &lag_engine_avg_load_ctl, 0);
    cmd = DRV_IOW(EpeHeaderEditChanAvgLoadTimerCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_avg_load_ctl));

    for (j = 0; j < MCHIP_CAP(SYS_CAP_PER_DP_PHY_CHANNEL_NUM); j++)
    {
        cmd = DRV_IOR(DsEpeHeaderEditDreDiscountShift_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, j, cmd, &dre_shift));
        SetDsEpeHeaderEditDreDiscountShift(V, g_0_chanDreDiscountShift_f, &dre_shift, 1);
        SetDsEpeHeaderEditDreDiscountShift(V, g_1_chanDreDiscountShift_f, &dre_shift, 1);
        cmd = DRV_IOW(DsEpeHeaderEditDreDiscountShift_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, j, cmd, &dre_shift));
    }

    /* Config dlb flow pulse timer for Tp=1ms*/
    for (i=0;i<4;i++)
    {
        cmd = DRV_IOR(RefDivSlice0PPPulse_t+i, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ref_div_pp_pulse));
        SetRefDivSlice0PPPulse(V, cfgSlice0RefDivLagEngineFlowSetActiveUpdatePulse_f, &ref_div_pp_pulse, 40000000);
        SetRefDivSlice0PPPulse(V, cfgSlice0ResetDivLagEngineFlowSetActiveUpdatePulse_f, &ref_div_pp_pulse, 0);
        SetRefDivSlice0PPPulse(V, cfgSlice0RefDivEpeHdrEditChanAvgLoadPulse_f, &ref_div_pp_pulse, 40000); /*1us*/
        SetRefDivSlice0PPPulse(V, cfgSlice0ResetDivEpeHdrEditChanAvgLoadPulse_f, &ref_div_pp_pulse, 0);
        cmd = DRV_IOW(RefDivSlice0PPPulse_t+i, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ref_div_pp_pulse));
    }


    /*4.config thrd*/
    /*sample period 1us in 1G speed, when 5G speed, need multiply the fator 5.
      quality  Threshold(bytes)
      0        120 ~ 125
      1        112 ~ 120
      2        104 ~ 112
      3        96  ~ 104
      4        88  ~ 96
      5        80  ~ 88
      6        72  ~ 80
      7        64  ~ 72
      8        56  ~ 64
      9        48  ~ 56
      10       40  ~ 48
      11       32  ~ 40
      12       24  ~ 32
      13       16  ~ 24
      14       8   ~ 16
      15       0   ~ 8
    */
    CTC_ERROR_RETURN(_sys_at_linkagg_dlb_set_load_quality_threshold(lchip, 8, 120));/*max 125*/

    /*5.config ErmChanAvgSizeTimerCtl */
    cmd = DRV_IOW(ErmChanAvgSizeTimerCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_avg_qdepth_ctl));
    SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerInterval_f, &lag_engine_avg_qdepth_ctl, 10);
    SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerEn_f, &lag_engine_avg_qdepth_ctl, 1);
    SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerEwmaMode_f, &lag_engine_avg_qdepth_ctl, 0);
    SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerEwmaWeight_f, &lag_engine_avg_qdepth_ctl, 0);
    SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerSliceEnVec_f, &lag_engine_avg_qdepth_ctl, SYS_PP_BMP(lchip));
    cmd = DRV_IOW(ErmChanAvgSizeTimerCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_avg_qdepth_ctl));

    cmd = DRV_IOR(ErmChanSizeUpdateCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &chan_size_updte));
    SetErmChanSizeUpdateCtl(V, chanSizeUpdateEn_f, &chan_size_updte, 1);
    cmd = DRV_IOW(ErmChanSizeUpdateCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &chan_size_updte));

    /*6.config thrd*/
    CTC_ERROR_RETURN(_sys_at_linkagg_dlb_set_qdepth_quality_threshold(lchip, 0, MCHIP_CAP(SYS_CAP_QOS_DROP_TOTAL_UC_POOL_SIZE)/100));

    /*7.config EpeHeaderEditChanLoadUpdateCtl */
    cmd = DRV_IOR(EpeHeaderEditChanLoadUpdateCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_dlb_ctl));
    SetEpeHeaderEditChanLoadUpdateCtl(V, chanLoadUpdateEn_f, &lag_engine_dlb_ctl, 1);
    SetEpeHeaderEditChanLoadUpdateCtl(V, byteCountShift_f, &lag_engine_dlb_ctl, 0);  /* unit of dre counter */
    SetEpeHeaderEditChanLoadUpdateCtl(V, ipg_f, &lag_engine_dlb_ctl, 20);     /* for dre ipg */
    SetEpeHeaderEditChanLoadUpdateCtl(V, chanHisLoadUpdateMode_f, &lag_engine_dlb_ctl, 0); /* default dre;0:dre 1:ewma*/
    cmd = DRV_IOW(EpeHeaderEditChanLoadUpdateCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_dlb_ctl));

    /*8.config LagEngineCtl_m*/
    cmd = DRV_IOR(LagEngineCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_ctl));
    SetLagEngineCtl(V, portLagMemberMoveCheckEn_f, &lag_engine_ctl, 3);
    SetLagEngineCtl(V, rrProtectDisable_f,&lag_engine_ctl, 0);
    SetLagEngineCtl(V, iLoopOamDestId_f, &lag_engine_ctl, SYS_RSV_PORT_ILOOP_ID);
    cmd = DRV_IOW(LagEngineCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &lag_engine_ctl));

    value = 1;
    cmd = DRV_IOW(LagEngineLinkState_t, LagEngineLinkState_linkState_f);
    for(chan_id=0; chan_id < MCHIP_CAP(SYS_CAP_CHANNEL_NUM); chan_id++)
    {
        if (!SYS_IS_NETWORK_CHANNEL(chan_id))
        {
            continue;
        }
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, chan_id, cmd, &value));
    }
    return CTC_E_NONE;
}

int32
sys_at_linkagg_dlb_set_config(uint8 lchip, void* p_cfg)
{
    uint32 cmd = 0;
    uint32 field_val = 0;
    uint16 chan_id = 0;
    uint16 loop = 0;
    uint16 step = 0;
    ctc_global_lag_dlb_property_t* p_dlb_cfg = (ctc_global_lag_dlb_property_t*)p_cfg;
    ds_t ds;

    SYS_LINKAGG_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_dlb_cfg);
    CTC_MAX_VALUE_CHECK(p_dlb_cfg->mode, CTC_LAG_DLB_MODE_MAX - 1);
    CTC_MAX_VALUE_CHECK(p_dlb_cfg->port_weight, 0xF);
    CTC_MAX_VALUE_CHECK(p_dlb_cfg->queue_weight, 0xF);
    CTC_MAX_VALUE_CHECK(p_dlb_cfg->queue_percent, 100);
    CTC_MAX_VALUE_CHECK((p_dlb_cfg->interval * 156250 / 1000), 0xFFFFFF);

    /*check mode*/
    switch (p_dlb_cfg->mode)
    {
        case CTC_LAG_DLB_MODE_PORT:
            if (0 != p_dlb_cfg->queue_percent)
            {
                return CTC_E_INVALID_PARAM;
            }
            break;
        case CTC_LAG_DLB_MODE_QUEUE:
            if (!p_dlb_cfg->calc_type || 100 != p_dlb_cfg->queue_percent || p_dlb_cfg->interval)
            {
                return CTC_E_INVALID_PARAM;
            }
            break;
        case CTC_LAG_DLB_MODE_PORT_QUEUE:
            if (!p_dlb_cfg->calc_type
                || 100 == p_dlb_cfg->queue_percent
                || 0 == p_dlb_cfg->queue_percent)
            {
                return CTC_E_INVALID_PARAM;
            }
            break;
        default:
            return CTC_E_INVALID_PARAM;
    }

    if(p_dlb_cfg->interval)
    {
        CTC_ERROR_RETURN(_sys_at_linkagg_dlb_set_load_quality_threshold(lchip, 8 * p_dlb_cfg->interval, 120 * p_dlb_cfg->interval));

        field_val = (p_dlb_cfg->interval * 156250 / 1000) << 8 | (p_dlb_cfg->interval * 156250 % 1000 * 256 / 1000);
        if (p_dlb_cfg->mode == CTC_LAG_DLB_MODE_PORT || p_dlb_cfg->mode == CTC_LAG_DLB_MODE_PORT_QUEUE)
        {
            step = RefDivSlice1PPPulse_t - RefDivSlice0PPPulse_t;
            for (loop = 0; loop < 4; loop++)
            {   
                cmd = DRV_IOR(RefDivSlice0PPPulse_t + step * loop, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
                SetRefDivSlice0PPPulse(V, cfgSlice0RefDivEpeHdrEditChanAvgLoadPulse_f, &ds, field_val);
                SetRefDivSlice0PPPulse(V, cfgSlice0ResetDivEpeHdrEditChanAvgLoadPulse_f, &ds, 0);
                cmd = DRV_IOW(RefDivSlice0PPPulse_t + step * loop, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
            }
        }        
    }

    /*config ewma enable*/
    cmd = DRV_IOR(EpeHeaderEditChanLoadUpdateCtl_t, EpeHeaderEditChanLoadUpdateCtl_chanHisLoadUpdateMode_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val));
    if (field_val != p_dlb_cfg->calc_type)
    {
        field_val = p_dlb_cfg->calc_type ? 1 : 0;
        cmd = DRV_IOR(EpeHeaderEditChanLoadUpdateCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        SetEpeHeaderEditChanLoadUpdateCtl(V, chanHisLoadUpdateMode_f, &ds, field_val);
        cmd = DRV_IOW(EpeHeaderEditChanLoadUpdateCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));

        /*clear state*/
        for (chan_id = 0; chan_id < MCHIP_CAP(SYS_CAP_CHANNEL_NUM); chan_id++)
        {
            cmd = DRV_IOR(DsLagDlbChanAvgLoadQuality_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));
            SetDsLagDlbChanAvgLoadQuality(V, chanQuality_f, &ds, 0);
            cmd = DRV_IOW(DsLagDlbChanAvgLoadQuality_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));

            cmd = DRV_IOR(DsEcmpDlbChanAvgLoadQuality_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));
            SetDsEcmpDlbChanAvgLoadQuality(V, chanQuality_f, &ds, 0);
            cmd = DRV_IOW(DsEcmpDlbChanAvgLoadQuality_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));
        }

        for (loop = 0; loop < MCHIP_CAP(SYS_CAP_DP_MAX_NUM); loop++)
        {
            for (chan_id = 0; chan_id <  MCHIP_CAP(SYS_CAP_PER_DP_CHANNEL_NUM); chan_id++)
            {
                cmd = DRV_IOR(DsEpeHeaderEditChannelByteCounterHis_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, ((chan_id << 1) + loop), cmd, &ds));
                SetDsEpeHeaderEditChannelByteCounterHis(V, dreCount_f, &ds, 0);
                cmd = DRV_IOW(DsEpeHeaderEditChannelByteCounterHis_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, ((chan_id << 1) + loop), cmd, &ds));

                cmd = DRV_IOR(DsEpeHeaderEditChannelByteCounterCur_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, ((chan_id << 1) + loop), cmd, &ds));
                SetDsEpeHeaderEditChannelByteCounterCur(V, byteCount_f, &ds, 0);
                cmd = DRV_IOW(DsEpeHeaderEditChannelByteCounterCur_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN(DRV_IOCTL(lchip, ((chan_id << 1) + loop), cmd, &ds));
            }
        }
    }

    if (p_dlb_cfg->calc_type)
    {
        cmd = DRV_IOR(EpeHeaderEditChanAvgLoadTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        SetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEwmaWeight_f, &ds, p_dlb_cfg->port_weight);
        cmd = DRV_IOW(EpeHeaderEditChanAvgLoadTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));

        cmd = DRV_IOR(ErmChanAvgSizeTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        SetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerEwmaWeight_f, &ds, p_dlb_cfg->queue_weight);
        cmd = DRV_IOW(ErmChanAvgSizeTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
    }
    else
    {
        /*config load dre shift*/
        for (chan_id = 0; chan_id <  MCHIP_CAP(SYS_CAP_PER_DP_CHANNEL_NUM); chan_id++)
        {
            cmd = DRV_IOR(DsEpeHeaderEditDreDiscountShift_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));
            SetDsEpeHeaderEditDreDiscountShift(V, g_0_chanDreDiscountShift_f, &ds, p_dlb_cfg->port_weight);
            SetDsEpeHeaderEditDreDiscountShift(V, g_1_chanDreDiscountShift_f, &ds, p_dlb_cfg->port_weight);
            cmd = DRV_IOW(DsEpeHeaderEditDreDiscountShift_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, chan_id, cmd, &ds));
        }
    }

    /*config quality mapping*/
    CTC_ERROR_RETURN(_sys_tmm_linkagg_dlb_set_quality_map(lchip, 100 - p_dlb_cfg->queue_percent));

    return CTC_E_NONE;
}

int32
sys_at_linkagg_dlb_get_config(uint8 lchip, void* p_cfg)
{
    uint32 cmd = 0;
    uint32 field_val = 0;
    ctc_global_lag_dlb_property_t* p_dlb_cfg = (ctc_global_lag_dlb_property_t*)p_cfg;
    ds_t ds;

    SYS_LINKAGG_INIT_CHECK();
    CTC_PTR_VALID_CHECK(p_dlb_cfg);

    if (100 == p_usw_linkagg_master[lchip]->tx_load_percent)
    {
        p_dlb_cfg->mode = CTC_LAG_DLB_MODE_PORT;
    }
    else if (0 == p_usw_linkagg_master[lchip]->tx_load_percent)
    {
        p_dlb_cfg->mode = CTC_LAG_DLB_MODE_QUEUE;
    }
    else
    {
        p_dlb_cfg->mode = CTC_LAG_DLB_MODE_PORT_QUEUE;
    }

    if (p_dlb_cfg->mode == CTC_LAG_DLB_MODE_PORT || p_dlb_cfg->mode == CTC_LAG_DLB_MODE_PORT_QUEUE)
    {
        cmd = DRV_IOR(RefDivSlice0PPPulse_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        field_val = GetRefDivSlice0PPPulse(V, cfgSlice0RefDivEpeHdrEditChanAvgLoadPulse_f, &ds);
        p_dlb_cfg->interval = ((field_val >> 8) * 1000 + (field_val & 0xFF) * 1000 / 256) / 156250;
    }

    /*get ewma enable*/
    cmd = DRV_IOR(EpeHeaderEditChanLoadUpdateCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
    p_dlb_cfg->calc_type = GetEpeHeaderEditChanLoadUpdateCtl(V, chanHisLoadUpdateMode_f,&ds);

    if(p_dlb_cfg->calc_type)
    {
        cmd = DRV_IOR(EpeHeaderEditChanAvgLoadTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        p_dlb_cfg->port_weight = GetEpeHeaderEditChanAvgLoadTimerCtl(V, chanAvgLoadTimerEwmaWeight_f, &ds);

        cmd = DRV_IOR(ErmChanAvgSizeTimerCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        p_dlb_cfg->queue_weight = GetErmChanAvgSizeTimerCtl(V, chanAvgSizeTimerEwmaWeight_f, &ds);
    }
    else
    {

        cmd = DRV_IOR(DsEpeHeaderEditDreDiscountShift_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ds));
        p_dlb_cfg->port_weight = GetDsEpeHeaderEditDreDiscountShift(V, g_0_chanDreDiscountShift_f, &ds);    
    }

    /*get quality mapping*/
    p_dlb_cfg->queue_percent = 100 - p_usw_linkagg_master[lchip]->tx_load_percent;

    return CTC_E_NONE;
}

int32
sys_at_linkagg_update_mirror_dest(uint8 lchip, uint16 tid, uint8 is_set)
{
    uint32 cmd = 0;
    uint8  loop =  0;
    uint8  member_cnt = 0;
    uint32 member_list[SYS_LINKAGG_MIRROR_MEMBER_NUM_MAX] = {0};
    uint8  step = DsMetFifoExcpLinkAggregation_g_1_destChipId_f - DsMetFifoExcpLinkAggregation_g_0_destChipId_f;
    sys_linkagg_t* p_group = NULL;
    DsMetFifoExcpLinkAggregation_m ds_excp_linkaggregation;

    p_group = ctc_vector_get(p_usw_linkagg_master[lchip]->group_vector, tid);
    if (!p_group)
    {
        return CTC_E_NOT_EXIST;
    }

    cmd = DRV_IOR(DsMetFifoExcpLinkAggregation_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tid, cmd, &ds_excp_linkaggregation));

    member_cnt = SYS_LINKAGG_MIRROR_MEMBER_NUM_MAX;
    CTC_ERROR_RETURN(_sys_usw_linkagg_get_ports2(lchip, p_group, member_list, &member_cnt));

    for (loop = 0; loop < member_cnt; loop++)
    {
        SetDsMetFifoExcpLinkAggregation(V, g_0_destChipId_f + loop*step, &ds_excp_linkaggregation, CTC_MAP_GPORT_TO_GCHIP(member_list[loop]));
        SetDsMetFifoExcpLinkAggregation(V, g_0_destId_f + loop*step, &ds_excp_linkaggregation, CTC_MAP_GPORT_TO_LPORT(member_list[loop]));
    }

    if (0 == member_cnt || !is_set)
    {
        SetDsMetFifoExcpLinkAggregation(V, g_0_destId_f, &ds_excp_linkaggregation, MCHIP_CAP(SYS_CAP_RSV_PORT_DROP_ID));
        SetDsMetFifoExcpLinkAggregation(V, linkAggMemNum_f, &ds_excp_linkaggregation, 0);
    }
    else
    {
        SetDsMetFifoExcpLinkAggregation(V, linkAggMemNum_f, &ds_excp_linkaggregation, member_cnt - 1);
    }

    cmd = DRV_IOW(DsMetFifoExcpLinkAggregation_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, tid, cmd, &ds_excp_linkaggregation));

    return CTC_E_NONE;
}

STATIC int32
_sys_at_linkagg_update_nonuc_hash_dest_pp_mask(uint8 lchip, sys_linkagg_t* p_group)
{
    uint32 cmd   = 0;
    uint32 pp_id  = 0;
    uint16 pp_bmp = 0;
    uint16 hash_value = 0;
    uint16 mem_idx = 0;
    uint32 fld_id = 0;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    DsPreMetRepHash_m rep_hash;

    if (0 == p_group->xfabric_type)
    {
        return CTC_E_NONE;
    }


    fld_id = (1 == p_group->xfabric_type)? DsPreMetRepHash_g0_0_repVec_f : DsPreMetRepHash_g1_0_repVec_f;

    for(hash_value = 0; (hash_value < SYS_LINKAGG_LB_HASH_MAX); hash_value++)
    {
        pp_bmp = 0;
        if (p_group->port_cnt)
        {
            mem_idx = hash_value % p_group->port_cnt;
            dmps_port_info.gport = p_group->port_list[mem_idx]->gport;
            CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PP_ID, &pp_id));
            CTC_BIT_SET(pp_bmp, pp_id);
        }
        if (0 == (hash_value & 0x1F))
        {
            cmd = DRV_IOR(DsPreMetRepHash_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hash_value >> 5, cmd, &rep_hash));
        }
        DRV_SET_FIELD_V(lchip, DsPreMetRepHash_t, fld_id + (hash_value & 0x1F), &rep_hash, pp_bmp);
        if(0 == ((hash_value + 1) & 0x1F))
        {
            cmd = DRV_IOW(DsPreMetRepHash_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hash_value >> 5, cmd, &rep_hash));
        }
    }

    return CTC_E_NONE;
}

int32
sys_at_linkagg_update_nonuc_ports_by_pp(uint8 lchip, void* p_lag_group, uint32 gport,
                                                               uint32* port_bitmap_old, uint32* port_bitmap_new, uint8 op)
{
    uint32 cmd = 0;
    uint32 port_bitmap_tmp[SYS_MAX_PP_NUM][CTC_PORT_BITMAP_IN_WORD] = {{0}};
    uint32  pp_id = 0;
    uint8  loop = 0;
    uint8  loop2 = 0;
    sys_linkagg_t* p_group = NULL;
    sys_usw_dmps_port_info_t dmps_port_info = {0};
    DsMetNonUcLagMemberBitmap_m member_bitmap;

    p_group = (sys_linkagg_t*)p_lag_group;

    /*1. get old bitmap by hw*/
    for (loop = 0; loop < SYS_PP_NUM(lchip); loop++)
    {
        cmd = DRV_IOR(DsMetNonUcLagMemberBitmap_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(loop, p_group->tid, DRV_CMD_PP_EN(cmd), &member_bitmap));
        GetDsMetNonUcLagMemberBitmap(A, portBitmap_f, &member_bitmap, port_bitmap_tmp[loop]);
        for (loop2 = 0 ; loop2 < CTC_PORT_BITMAP_IN_WORD; loop2++)
        {
            port_bitmap_old[loop2] |= port_bitmap_tmp[loop][loop2];
        }
    }

    /*2. build new bitmap(per pp) for hw*/
    dmps_port_info.gport = gport;
    CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PP_ID, &pp_id));
    if (SYS_LINKAGG_OP_ADD == op)
    {
        CTC_BMP_SET(port_bitmap_tmp[pp_id], CTC_MAP_GPORT_TO_LPORT(gport));
    }
    else if (SYS_LINKAGG_OP_DEL == op)
    {
        CTC_BMP_UNSET(port_bitmap_tmp[pp_id], CTC_MAP_GPORT_TO_LPORT(gport));
    }
    else if (SYS_LINKAGG_OP_REP == op)
    {
        sal_memset(port_bitmap_tmp, 0, sizeof(port_bitmap_tmp));
        for (loop = 0 ; loop < p_group->port_cnt; loop++)
        {
            dmps_port_info.gport = p_group->port_list[loop]->gport;
            CTC_ERROR_RETURN(sys_usw_port_api_get_dmps_property(lchip, &dmps_port_info, SYS_PORT_API_DMPS_PROP_PP_ID, &pp_id));
            CTC_BMP_SET(port_bitmap_tmp[pp_id], CTC_MAP_GPORT_TO_LPORT(p_group->port_list[loop]->gport));
        }
    }

    /*3. write hw*/
    for (loop = 0; loop < SYS_PP_NUM(lchip); loop++)
    {
        SetDsMetNonUcLagMemberBitmap(A, portBitmap_f, &member_bitmap, port_bitmap_tmp[loop]);
        cmd = DRV_IOW(DsMetNonUcLagMemberBitmap_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(loop, p_group->tid, DRV_CMD_PP_EN(cmd), &member_bitmap));
    }

    /*4. build new bitmap*/
    for (loop = 0 ; loop < p_group->port_cnt; loop++)
    {
        CTC_BMP_SET(port_bitmap_new, CTC_MAP_GPORT_TO_LPORT(p_group->port_list[loop]->gport));
    }

    /*5. update DsPreMetRepHash for uplink*/
    if (p_group->xfabric_type)
    {
        CTC_ERROR_RETURN(_sys_at_linkagg_update_nonuc_hash_dest_pp_mask(lchip, p_group));
    }

    return CTC_E_NONE;
}


int32
sys_at_linkagg_loop_chan_lag_en(uint8 lchip, uint32 enable)
{
    int32 ret = CTC_E_NONE;
    ctc_linkagg_group_t chan_lag;
    uint8 tid = 0;
    uint32 lport = 0;
    uint32 cmd = 0;
    uint32 field_val = 0;
    DsPortChannelLag_m ds_chanagg_grp;
    uint8 pp_id = 0;
    uint8 pp_num = 0;

    pp_num = SYS_PP_NUM(lchip);
    for (pp_id = 0; pp_id < pp_num; pp_id++)
    {
        if (!enable)
        {
            _sys_usw_linkagg_destroy_channel_agg(lchip, MCHIP_CAP(SYS_CAP_LINKAGG_CHAN_GRP_MAX)-1-pp_id);
            sal_memset(&ds_chanagg_grp, 0, sizeof(ds_chanagg_grp));
            cmd = DRV_IOW(DsPortChannelLag_t, DRV_ENTRY_FLAG);
            DRV_IOCTL(lchip, MCHIP_CAP(SYS_CAP_RSV_PORT_ELOOP_ID)-pp_id, cmd, &ds_chanagg_grp);
            field_val = 0;
            cmd = DRV_IOW(DsMetPortChannelLag_t, DsMetPortChannelLag_chanLagEnable_f);
            DRV_FIELD_IOCTL(lchip, MCHIP_CAP(SYS_CAP_RSV_PORT_ELOOP_ID)-pp_id, cmd, &field_val);
            MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID) = MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID)+1;
        }
        else
        {
            /*1. default create pp channel linkagg group*/
            tid = MCHIP_CAP(SYS_CAP_LINKAGG_CHAN_GRP_MAX)-1-pp_id;
            sal_memset(&chan_lag, 0, sizeof(ctc_linkagg_group_t));
            chan_lag.tid = tid;
            chan_lag.linkagg_mode = CTC_LINKAGG_MODE_STATIC;
            CTC_ERROR_RETURN(_sys_usw_linkagg_create_channel_agg(lchip, &chan_lag));

            CTC_ERROR_GOTO(_sys_usw_linkagg_add_channel_member(lchip, tid, MCHIP_CAP(SYS_CAP_CHANID_ELOOP)+2*pp_id), ret, roll_back_0);
            CTC_ERROR_GOTO(_sys_usw_linkagg_add_channel_member(lchip, tid, MCHIP_CAP(SYS_CAP_CHANID_ELOOP)+2*pp_id+1), ret, roll_back_0);
            lport = MCHIP_CAP(SYS_CAP_RSV_PORT_ELOOP_ID)-pp_id;
            sal_memset(&ds_chanagg_grp, 0, sizeof(ds_chanagg_grp));
            SetDsPortChannelLag(V, linkAggregationChannelGroup_f, &ds_chanagg_grp, tid);
            cmd = DRV_IOW(DsPortChannelLag_t, DRV_ENTRY_FLAG);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, lport, cmd, &ds_chanagg_grp), ret, roll_back_0);
            field_val = 1;
            cmd = DRV_IOW(DsMetPortChannelLag_t, DsMetPortChannelLag_chanLagEnable_f);
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, lport, cmd, &field_val), ret, roll_back_0);
            MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID) = MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID)-1;
        }
    }

    return CTC_E_NONE;

roll_back_0:
    for (; pp_id >0; pp_id--)
    {
        _sys_usw_linkagg_destroy_channel_agg(lchip, MCHIP_CAP(SYS_CAP_LINKAGG_CHAN_GRP_MAX)-2-pp_id);
        MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID) = MCHIP_CAP(SYS_CAP_STK_TRUNK_MAX_ID)+1;
    }
    return ret;
}

#endif

